﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
using Microsoft.Win32;
using System.IO;


namespace Dialup_Tester
{
    public partial class MainForm : Form
    {
        // CONSTANTS

        const int PAUSE_WHILE_ONLINE = 3;
        
        // DECLARE GLOBAL STUFF HERE

        Dial MyDial = new Dial();
        Process RASDialProcess = new Process();

        RegistryKey regkey;

        string logFileName;

        CurrentStatus currentStatus;
        int PauseBetweenAttempts = 0;

        int counter = 0;

        bool Timer_ON = false;
        bool Testing_ON = false;

        enum CurrentStatus
        {
            NOT_STARTED,
            WAITING,
            DIALING,
            DISCONNECTED,
            ONLINE
        }

        int counter_Attempts_Total = 0;
        int counter_Attempts_Successfull = 0;
        int counter_Attempts_Errors = 0;
        int counter_Errors_NoAnswer = 0;
        int counter_Errors_BadCredentials = 0;
        int counter_Errors_Busy = 0;
        int counter_Errors_Other = 0;

        string DialUpArguments;

        // MAIN FORM CONSTRUCTOR
        
        public MainForm()
        {
            InitializeComponent();

            RASDialProcess.Exited += new EventHandler(checkExitCode);
            saveFileDialog1.FileOk += new CancelEventHandler(saveFileDialog1_FileOk);

            GetFormValuesFromRegistry();
        }

        private void GetFormValuesFromRegistry()
        {
            regkey = Registry.CurrentUser.OpenSubKey("Software\\dialup-tester\\Form Data",true);

            if (regkey == null)
            {
                regkey = Registry.CurrentUser.CreateSubKey("Software\\dialup-tester\\Form Data");
                regkey.SetValue("Connection", "");
                regkey.SetValue("Username", "");
                regkey.SetValue("Password", "");
                regkey.SetValue("Pause", "10");
                regkey.SetValue("Log", "");
            }
            
            try
            {
                textBox_Connection.Text = regkey.GetValue("Connection").ToString();
            }
            catch (NullReferenceException)
            {
                textBox_Connection.Text = "";
                regkey.SetValue("Connection", "");
            }

            try
            {
                textBox_User.Text = regkey.GetValue("Username").ToString();
            }
            catch (NullReferenceException)
            {
                textBox_User.Text = "";
                regkey.SetValue("Username", "");
            }

            try
            {
                textBox_Password.Text = regkey.GetValue("Username").ToString();
            }
            catch (NullReferenceException)
            {
                textBox_Password.Text = "";
                regkey.SetValue("Password", "");
            }

            try
            {
                textBox_Pause.Text = regkey.GetValue("Pause").ToString();
            }
            catch (NullReferenceException)
            {
                textBox_Pause.Text = "";
                regkey.SetValue("Pause", "10");
            }

            try
            {
                textBox_File.Text = regkey.GetValue("Log").ToString();
            }
            catch (NullReferenceException)
            {
                textBox_File.Text = "";
                regkey.SetValue("Log", "");
            }
        }

        // FORM DATA RETRIEVAL AND VALIDATION
        
        private void SaveFormDataToRegistry()
        {
            RegistryKey regkey = Registry.CurrentUser.OpenSubKey("Software\\dialup-tester\\Form Data",true);
            regkey.SetValue("Connection", textBox_Connection.Text);
            regkey.SetValue("Username", textBox_User.Text);
            regkey.SetValue("Password", textBox_Password.Text);
            regkey.SetValue("Pause", textBox_Pause.Text);
            regkey.SetValue("Log", textBox_File.Text);
        }
        
        private void RedrawStats()
        {
            label_Attempts_Total.Text = counter_Attempts_Total.ToString();
            label_Attempts_Successful.Text = counter_Attempts_Successfull.ToString();
            label_Attempts_Errors.Text = counter_Attempts_Errors.ToString();
            label_Errors_NoAnswer.Text = counter_Errors_NoAnswer.ToString();
            label_Errors_BadCredentials.Text = counter_Errors_BadCredentials.ToString();
            label_Errors_Busy.Text = counter_Errors_Busy.ToString();
            label_Errors_Other.Text = counter_Errors_Other.ToString();
        }

        private bool isConnectionNameOK()
        {
            if (textBox_Connection.Text == "")
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        private bool isPauseOK()
        {
            try
            {
                if ((Convert.ToInt32(textBox_Pause.Text) < 0))
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
            catch (FormatException)
            {
                return false;
            }
        }



        // MAIN CYCLE METHODS
        
        private void MakeDialupAttempt()
        {
            RASDialProcess.StartInfo.FileName = "C:\\Windows\\System32\\rasdial.exe";
            RASDialProcess.StartInfo.Arguments = DialUpArguments;
            RASDialProcess.EnableRaisingEvents = true;
            RASDialProcess.Start();
        }

        private void HangUp()
        {
            RASDialProcess.StartInfo.FileName = "C:\\Windows\\System32\\rasdial.exe";
            RASDialProcess.StartInfo.Arguments = "/DISCONNECT";
            RASDialProcess.EnableRaisingEvents = true;
            RASDialProcess.Start();
        }

        private void NextPlease()
        {
            if (currentStatus == CurrentStatus.NOT_STARTED) // Переход из  начальной стадии к стадии дозвона
            {
                button_Start.Enabled = false;
                currentStatus = CurrentStatus.DIALING;
                toolStripStatusLabel1.Text = "Текущее состояние: Набор номера";
                MakeDialupAttempt();
            }
            else if (currentStatus == CurrentStatus.WAITING) // Переход из стадии ожидания к дозвону
            {
                
                button_Start.Enabled = false;
                currentStatus = CurrentStatus.DIALING;
                toolStripStatusLabel1.Text = "Текущее состояние: Набор номера";
                MakeDialupAttempt();
            }
            else if (currentStatus == CurrentStatus.ONLINE) // Переход из состояния онлайн к разрыву соединения
            {
                toolStripStatusLabel1.Text = "Текущее состояние: Разрыв соединения";
                HangUp();
            }
            else if (currentStatus == CurrentStatus.DISCONNECTED) // Переход от разрыва соединения / недозвона к состоянию ожидания
            {
                currentStatus = CurrentStatus.WAITING;
                counter = PauseBetweenAttempts;
                Timer_ON = true;
            }
        }

        private void checkExitCode(object sender, EventArgs e)
        {
            Control.CheckForIllegalCrossThreadCalls = false; // not Thread-Safe

            if (currentStatus == CurrentStatus.DIALING) // Если была попытка дозвона
            {
                if (RASDialProcess.ExitCode == 0) // Успешная попытка
                {
                    currentStatus = CurrentStatus.ONLINE;
                    toolStripStatusLabel1.Text = "Текущее состояние: Соединение установлено";
                    counter_Attempts_Successfull++;
                    WriteToLog(logFileName, (DateTime.Now.ToString() + " - Успешное соединение"));
                    button_Start.Enabled = true;
                }
                else if (RASDialProcess.ExitCode == 691) // Неправильный пароль или пользователь
                {
                    currentStatus = CurrentStatus.WAITING;
                    toolStripStatusLabel1.Text = "Текущее состояние: Соединение не установлено";
                    counter_Attempts_Errors++;
                    counter_Errors_BadCredentials++;
                    WriteToLog(logFileName, (DateTime.Now + " - Ошибка (недопустимое имя пользователя или пароль)"));
                    button_Start.Enabled = true;
                }
                else if (RASDialProcess.ExitCode == 721) // Удаленный компьютер не ответил
                {
                    currentStatus = CurrentStatus.DISCONNECTED;
                    toolStripStatusLabel1.Text = "Текущее состояние: Соединение не установлено";
                    counter_Attempts_Errors++;
                    counter_Errors_NoAnswer++;
                    WriteToLog(logFileName, (DateTime.Now + " - Ошибка (удаленный компьютер не ответил)"));
                    button_Start.Enabled = true;
                }
                else if (RASDialProcess.ExitCode == 676) // Занято
                {
                    currentStatus = CurrentStatus.DISCONNECTED;
                    toolStripStatusLabel1.Text = "Текущее состояние: Соединение не установлено";
                    counter_Attempts_Errors++;
                    counter_Errors_Busy++;
                    WriteToLog(logFileName, (DateTime.Now + " - Ошибка (телефонная линия занята)"));
                    button_Start.Enabled = true;
                }
                else if (RASDialProcess.ExitCode == 680) // Отсутствует гудок
                {
                    currentStatus = CurrentStatus.DISCONNECTED;
                    toolStripStatusLabel1.Text = "Текущее состояние: Соединение не установлено";
                    counter_Attempts_Errors++;
                    counter_Errors_Other++;
                    WriteToLog(logFileName, (DateTime.Now + " - Ошибка (отсутствует гудок)"));
                    button_Start.Enabled = true;
                }
                else if (RASDialProcess.ExitCode == 1) // Руками отбито
                {
                    currentStatus = CurrentStatus.DISCONNECTED;
                    toolStripStatusLabel1.Text = "Текущее состояние: Соединение не установлено";
                    counter_Attempts_Errors++;
                    counter_Errors_Other++;
                    WriteToLog(logFileName, (DateTime.Now + " - Ошибка (закрыто окно дозвонщика)"));
                    button_Start.Enabled = true;
                }
                else // Другие ошибки
                {
                    currentStatus = CurrentStatus.DISCONNECTED;
                    toolStripStatusLabel1.Text = "Текущее состояние: Соединение не установлено";
                    counter_Attempts_Errors++;
                    counter_Errors_Other++;
                    WriteToLog(logFileName, (DateTime.Now + " - Ошибка (что-то еще)"));
                    button_Start.Enabled = true;
                }
                counter_Attempts_Total++;
                RedrawStats();
                NextPlease();
            }
            else if (currentStatus == CurrentStatus.ONLINE) // Если была попытка разъединения
            {
                if (RASDialProcess.ExitCode == 0) // Нормально
                {
                    currentStatus = CurrentStatus.DISCONNECTED;
                    toolStripStatusLabel1.Text = "Текущее состояние: Соединение разорвано";
                }
                else // Этого быть не должно
                {
                    throw new ApplicationException();
                }
                NextPlease();
            }

            Control.CheckForIllegalCrossThreadCalls = true; // Thread-Safe again
        }

        // FORM ELEMENTS STUFF
        
        private void button3_Click(object sender, EventArgs e)
        {
            RASDialProcess.StartInfo.FileName = "C:\\Windows\\System32\\rasdial.exe";
            RASDialProcess.StartInfo.Arguments = "/DISCONNECT";
            RASDialProcess.EnableRaisingEvents = true;
            RASDialProcess.Start();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (Timer_ON)
            {
                toolStripStatusLabel1.Text = "Текущее состояние: Ожидание следующей попытки (осталось " + counter.ToString() + " секунд)";
                
                if (counter == 0)
                {
                    Timer_ON = false;
                    NextPlease();
                }
                counter--;
            }
        }

        private void button_File_Click(object sender, EventArgs e)
        {
            saveFileDialog1.ShowDialog();
        }

        private void saveFileDialog1_FileOk(object sender, System.ComponentModel.CancelEventArgs e)
        {
            textBox_File.Text = saveFileDialog1.FileNames[0];
        }

        private void button_Start_Click(object sender, EventArgs e)
        {
            if (!Testing_ON)
            {
                if (!isConnectionNameOK())
                {
                    MessageBox.Show("Название соединения не может быть пустым");
                    return;
                }

                if (!isPauseOK())
                {
                    MessageBox.Show("Пауза между соединениями - целое неотрицательное число");
                    return;
                }
                
                SaveFormDataToRegistry();

                PauseBetweenAttempts = Convert.ToInt32(textBox_Pause.Text);

                logFileName = textBox_File.Text;

                WriteToLog(logFileName, (DateTime.Now + " - Начало тестирования (" + textBox_Connection.Text + ", " + textBox_User.Text + ")"));

                DialUpArguments = textBox_Connection.Text + " " + textBox_User.Text + " " + textBox_Password.Text;

                textBox_Connection.Enabled = false;
                textBox_File.Enabled = false;
                textBox_Pause.Enabled = false;
                textBox_User.Enabled = false;
                textBox_Password.Enabled = false;
                button_ChooseFile.Enabled = false;

                Testing_ON = true;
                button_Start.Text = "Остановить тестирование";

                NextPlease();
            }
            else
            {
                if (currentStatus == CurrentStatus.ONLINE)
                {
                    HangUp();
                }

                WriteToLog(logFileName, (DateTime.Now + " - Завершение тестирования (успешных соединений - "  + counter_Attempts_Successfull + ", ошибок - " + counter_Attempts_Errors + ")"));

                textBox_Connection.Enabled = true;
                textBox_File.Enabled = true;
                textBox_Pause.Enabled = true;
                textBox_User.Enabled = true;
                textBox_Password.Enabled = true;
                button_ChooseFile.Enabled = true;

                Timer_ON = false;
                Testing_ON = false;
                toolStripStatusLabel1.Text = "Текущее состояние: Ожидание начала тестирования";
                button_Start.Text = "Начать тестирование";

            }
        }

        private void WriteToLog(string logFileName, string whatToWrite)
        {
            if (File.Exists(logFileName))
            {
                StreamWriter sw = File.AppendText(logFileName);
                sw.WriteLine(whatToWrite);
                sw.Close();
            }
            else
            {
                try
                {
                    StreamWriter sw = File.CreateText(logFileName);
                    sw.WriteLine(whatToWrite);
                    sw.Close();
                }
                catch (ArgumentException)
                {
                }
            }


        }
    }
}